<?php
if (!function_exists('app_path')) {
    /**
     * 获取应用基础目录
     *
     * @param string $path
     * @return string
     */
    function app_path($path = '')
    {
        return \think\facade\Env::get("app_path") . ($path ? $path . DIRECTORY_SEPARATOR : $path);
    }
}

if (!function_exists('runtime_path')) {
    /**
     * 获取应用运行时目录
     *
     * @param string $path
     * @return string
     */
    function runtime_path($path = '')
    {
        return \think\facade\Env::get("runtime_path") . ($path ? $path . DIRECTORY_SEPARATOR : $path);
    }
}

if (!function_exists("get_module")) {
    /**
     * @Notes: 获取模块
     * @return string
     */
    function get_module()
    {
        return request()->module();
    }
}

if (!function_exists("get_controller")) {
    /**
     * @Notes: 获取控制器
     * @return string
     */
    function get_controller()
    {
        return request()->controller();
    }
}

if (!function_exists("get_action")) {
    /**
     * @Notes: 获取方法
     * @return string
     */
    function get_action()
    {
        return request()->action();
    }
}

if (!function_exists("humpToLine")) {
    /**
     * 驼峰转下划线
     * @param $str
     * @return null|string|string[]
     */
    function humpToLine($str)
    {
        $str = preg_replace_callback('/([A-Z]{1})/', function ($matches) {
            return '_' . strtolower($matches[0]);
        }, $str);
        return $str;
    }
}

if (!function_exists("scan_dir")) {
    /**
     * scan_dir的方法
     * @param string $pattern 检索模式 搜索模式 *.txt,*.doc; (同glog方法)
     * @param int $flags
     * @param        $pattern
     * @return array
     */
    function scan_dir($pattern, $flags = null)
    {
        $files = glob($pattern, $flags);
        if (empty($files)) {
            $files = [];
        } else {
            $files = array_map('basename', $files);
        }
        return $files;
    }
}

if (!function_exists('root_path')) {
    /**
     * 获取项目根目录
     *
     * @param string $path
     * @return string
     */

    function root_path($path = '')
    {
        return \think\facade\Env::get("root_path") . ($path ? $path . DIRECTORY_SEPARATOR : $path);
    }
}

if (!function_exists("get_option")) {
    /**
     * 获取系统配置，通用
     * @param string $key 配置键值,都小写
     * @return array
     */
    function get_option($key)
    {
        if (!is_string($key) || empty($key)) {
            return [];
        }

        if (PHP_SAPI != 'cli') {
            static $cmfGetOption;

            if (empty($cmfGetOption)) {
                $cmfGetOption = [];
            } else {
                if (!empty($cmfGetOption[$key])) {
                    return $cmfGetOption[$key];
                }
            }
        }

        $optionValue = cache('options_' . $key);

        if (empty($optionValue)) {
            $optionValue = \think\Db::name('option')->where('option_name', $key)->value('option_value');
            if (!empty($optionValue)) {

                $optionValue = json_decode($optionValue, true);

                cache('options_' . $key, $optionValue);
            }
        }

        $cmfGetOption[$key] = $optionValue;

        return $optionValue;
    }

}

if (!function_exists('clear_cache')) {
    /**
     * 清空系统缓存
     */
    function clear_cache()
    {
        // 清除 opcache缓存
        if (function_exists("opcache_reset")) {
            opcache_reset();
        }

        $dirs = [];
        $rootDirs = scan_dir(runtime_path() . "*");
        //$noNeedClear=array(".","..","Data");
        $noNeedClear = ['.', '..', 'log'];
        $rootDirs = array_diff($rootDirs, $noNeedClear);
        foreach ($rootDirs as $dir) {

            if ($dir != "." && $dir != "..") {
                $dir = runtime_path() . $dir;
                if (is_dir($dir)) {
                    //array_push ( $dirs, $dir );
                    $tmpRootDirs = scan_dir($dir . "/*");
                    foreach ($tmpRootDirs as $tDir) {
                        if ($tDir != "." && $tDir != "..") {
                            $tDir = $dir . '/' . $tDir;
                            if (is_dir($tDir)) {
                                array_push($dirs, $tDir);
                            } else {
//                            @unlink($tDir);
                            }
                        }
                    }
                } else {
//                @unlink($dir);
                }
            }
        }
        $dirTool = new \Dir\Dir("");
        foreach ($dirs as $dir) {
            $dirTool->delDir($dir);
        }
    }
}

if (!function_exists('get_user')) {
    /**
     * @Notes:获取用户 可以指定获取
     * @User: chenping
     * @email: 375129701@qq.com
     * @param $key
     * @return bool
     */
    function get_user($key = '', $build = '')
    {
        $adminUser = json_decode(\think\facade\Cookie::get("adminUser"), true);
        if (!$adminUser) {
            if ($build) {
                $adminUser = \think\Db::name("admin")
                    ->whereOr("username", $build)
                    ->whereOr("phone", $build)
                    ->whereOr("email", $build)
                    ->find()
                    ->toArray();
            }
        }
        if (is_string($key) && isset($adminUser[$key])) {
            return $adminUser[$key];
        }
        if (empty($key) or empty($build)) {
            return $adminUser;
        }
    }
}

if (!function_exists("get_access_node")) {
    /**
     * @Notes: 获取权限节点
     * @User: chenping
     * @email: 375129701@qq.com
     * @param string $uid
     * @return array|mixed
     */
    function get_access_node($uid = '', $is_menu = 0)
    {
        $uid = $uid ? $uid : get_user("id");

        $nodeList = \think\facade\Cache::get($uid . "_nodeList");

        if ($nodeList) return $nodeList;

        //超级管理员识别
        $SUPER_ADMIN_ID = \app\common\constants\AdminConstant::SUPER_ADMIN_ID;

        //指定获取数据
        $where = [];
        //获取菜单数据
        if ($is_menu == 1) array_push($where, ['is_menu', 'eq', 1]);

        if ($uid != $SUPER_ADMIN_ID) {
            //获取用户组
            $roleList = \think\Db::name('auth_group_access')
                ->where("uid", $uid)
                ->cache($uid . "_groups_ids")
                ->column("group_id");
            $groups = \think\Db::name("auth_group")
                ->whereIn("id", $roleList)
                ->field("rules")
                ->cache($uid . "_groups")
                ->select();
            //获取权限节点
            //保存用户所属用户组设置的所有权限规则id
            $ids = array();
            foreach ($groups as $g) {
                $ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
            }
            $ids = array_unique($ids);
            if (empty($ids)) {
                return array();
            }
            array_push($where, ['id', "in", $ids]);
        }
        $nodeList = \think\Db::name('auth_rule')
            ->where($where)
            ->column("name");
        \think\facade\Cache::set($uid . "_nodeList", $nodeList);
        return array_unique($nodeList);
    }

}

if (!function_exists("get_access_menu")) {
    /**
     * @Notes: 获取访问的权限菜单
     * @User: chenping
     * @email: 375129701@qq.com
     * @param string $uid
     * @return array|mixed
     */
    function get_access_menu($uid = '')
    {
        $uid = $uid ? $uid : get_user("id");

        $nodeList = get_access_node($uid ? $uid : get_user("id"), 1);

        $menuList = \think\facade\Cache::get($uid . '_menuList');

        if ($menuList) return $menuList;

        $menuList = \app\admin\model\system\Menu::whereIn('name', $nodeList)
            ->field("id,url_link as href,name,title as text,icon ,is_view as hasView,parent_id")
            ->where("status", 1)
            ->select()
            ->toArray();

        \think\facade\Cache::set($uid . '_menuList', $menuList);

        return $menuList;
    }


}

if (!function_exists("get_version")) {
    /**
     * @Notes:获取当前系统版本
     * @User: chenping
     * @email: 375129701@qq.com
     * @return array|null|PDOStatement|string|\think\Model
     */
    function get_version()
    {
        $version = \app\admin\model\system\Version::order("update_time", "desc")
            ->cache(true)
            ->field("author,version_number,version_code")
            ->find();
        return $version;
    }
}

/**
 * @Notes:api 目录
 * @User: chenping
 * @email: 375129701@qq.com
 * @param string $path
 * @return string
 */
function get_api_path($path = 'api')
{
    return app_path() . $path . DIRECTORY_SEPARATOR;
}

/**
 * @Notes:命令执行函数
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $cmd
 * @return string "ls"
 */
function command_exec($cmd)
{
    chdir(root_path());
    return exec($cmd);
}

/**
 * @Notes:验证手机
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $phone
 * @return bool
 */
function valiDatePhone($phone)
{
    if (preg_match("/^1[3-9]{1}[0-9]{9}$/", $phone)) {
        return true;
    } else {
        return false;
    }
}

/**
 * @Notes:验证电子邮件
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $email
 * @return bool
 */
function valiDateEmail($email)
{
    $result = trim($email);
    if (filter_var($result, FILTER_VALIDATE_EMAIL)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 二维数组排序
 * @param array $arr 需要排序的二维数组
 * @param string $keys 所根据排序的key
 * @param string $type 排序类型，desc、asc
 * @return array $new_array 排好序的结果
 */
function array_sort($arr, $keys, $type = 'desc')
{
    $key_value = $new_array = array();
    foreach ($arr as $k => $v) {
        $key_value[$k] = $v[$keys];
    }
    if ($type == 'asc') {
        asort($key_value);
    } else {
        arsort($key_value);
    }
    reset($key_value);
    foreach ($key_value as $k => $v) {
        $new_array[$k] = $arr[$k];
    }
    return $new_array;
}

/**
 * 设置系统配置，通用
 * @param string $key 配置键值,都小写
 * @param array $data 配置值，数组
 * @param bool $replace 是否完全替换
 * @return bool 是否成功
 * @throws \think\Exception
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 * @throws \think\exception\PDOException
 */
function set_option($key, $data, $replace = false)
{
    if (!is_array($data) || empty($data) || !is_string($key) || empty($key)) {
        return false;
    }

    $key = strtolower($key);
    $option = [];
    $findOption = \think\Db::name('option')->where('option_name', $key)->find();
    if ($findOption) {
        if (!$replace) {
            $oldOptionValue = json_decode($findOption['option_value'], true);
            if (!empty($oldOptionValue)) {
                $data = array_merge($oldOptionValue, $data);
            }
        }

        $option['option_value'] = json_encode($data);
        \think\Db::name('option')->where('option_name', $key)->update($option);
    } else {
        $option['option_name'] = $key;
        $option['option_value'] = json_encode($data);
        \think\Db::name('option')->insert($option);
    }
    cache('options_' . $key, null);
    return true;
}


/**
 * 发送邮件
 * @param string $address 收件人邮箱
 * @param string $subject 邮件标题
 * @param string $message 邮件内容
 * @return array<br>
 *                        返回格式：<br>
 *                        array(<br>
 *                        "error"=>0|1,//0代表出错<br>
 *                        "message"=> "出错信息"<br>
 *                        );
 * @throws phpmailerException
 */
function send_email($address, $subject, $message,$attachment='')
{
    $smtpSetting = get_option('smtp_setting');
    $mail = new \PHPMailer\PHPMailer\PHPMailer();
    // 设置PHPMailer使用SMTP服务器发送Email
    $mail->IsSMTP();
    $mail->IsHTML(true);
    //$mail->SMTPDebug = 3;
    // 设置邮件的字符编码，若不指定，则为'UTF-8'
    $mail->CharSet = 'UTF-8';
    // 添加收件人地址，可以多次使用来添加多个收件人
    $mail->AddAddress($address);
    // 设置邮件正文
    $mail->Body = $message;
    // 设置邮件头的From字段。
    $mail->From = $smtpSetting['from'];
    // 设置发件人名字
    $mail->FromName = $smtpSetting['from_name'];
    // 设置邮件标题
    $mail->Subject = $subject;
    // 设置SMTP服务器。
    $mail->Host = $smtpSetting['host'];
    //by Rainfer
    // 设置SMTPSecure。
    $Secure = $smtpSetting['smtp_secure'];
    $mail->SMTPSecure = empty($Secure) ? '' : $Secure;
    // 设置SMTP服务器端口。
    $port = $smtpSetting['port'];
    $mail->Port = empty($port) ? "25" : $port;
    // 设置为"需要验证"
    $mail->SMTPAuth = true;
    $mail->SMTPAutoTLS = false;
    $mail->Timeout = 10;
    // 设置用户名和密码。
    $mail->Username = $smtpSetting['username'];
    $mail->Password = $smtpSetting['password'];

    //添加附件
    if($attachment)
    {
        $ext = pathinfo($attachment);
        $mail->AddAttachment($attachment, $subject.".".$ext['extension'], $encoding = 'base64', $type = 'application/pdf');
    }

    // 发送邮件。
    if (!$mail->Send()) {
        $mailError = $mail->ErrorInfo;
        return ["error" => 1, "message" => $mailError];
    } else {
        return ["error" => 0, "message" => "success"];
    }
}

/**
 * 获取插件类名
 * @param string $name 插件名
 * @return string
 */
function get_plugin_class($name)
{
    $name = ucwords($name);
    $pluginDir = parse_name($name);
    $class = "addons\\{$pluginDir}\\{$name}";
    return $class;
}

/**
 * @Notes:解析插件配置页面
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $param
 * @return string
 */
function _parse_plugin_config($param)
{
    $config = '';
    foreach ($param as $k => $v) {
        switch ($v['type']) {
            case "select":
                $option = '';
                foreach ($v['options'] as $ks => $vo) {
                    if ($v['value'] == $ks) {
                        $option .= '<option value="' . $ks . '" selected >' . $vo . '</option>';
                    } else {
                        $option .= '<option value="' . $ks . '" >' . $vo . '</option>';
                    }
                }
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    '<select name="config[' . $k . ']" id="' . $k . '">' .
                    $option .
                    '</select>' .
                    '</div>' .
                    '</div>';
                break;
            case "checkbox":
                $option = '';
                foreach ($v['options'] as $ks => $vo) {
                    if (is_array($v['value']) && in_array($ks, $v['value'])) {
                        $option .= '<input type="checkbox"  class="layui-input" name="config[' . $k . '][]" title="' . $vo . '" checked value="' . $ks . '">';

                    } else {
                        $option .= '<input type="checkbox"  class="layui-input" name="config[' . $k . '][]" title="' . $vo . '"  value="' . $ks . '">';
                    }
                }
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    $option .
                    '</div>' .
                    '</div>';
                break;

            case "radio":
                $option = '';
                foreach ($v['options'] as $ks => $vo) {
                    if ($v['value'] == $ks) {
                        $option .= '<input type="radio"  class="layui-input" name="config[' . $k . ']"  title="' . $vo . '" checked value="' . $ks . '">';
                    } else {
                        $option .= '<input type="radio"  class="layui-input" name="config[' . $k . ']" title="' . $vo . '"  value="' . $ks . '">';
                    }
                }
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    $option .
                    '</div>' .
                    '</div>';
                break;
            case "textarea":
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    '<textarea name="config[' . $k . ']"  cols="30" rows="10" class="layui-textarea">' . $v['value'] . '</textarea>' .
                    '</div>' .
                    '</div>';
                break;
            case "password":
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    '<input type="password" class="layui-input" name="config[' . $k . ']" value="' . $v['value'] . '">' .
                    '</div>' .
                    '</div>';
                break;
            default:
                $config .= '<div class="layui-form-item">' .
                    '<label class="layui-form-label">' . $v['title'] . '</label>' .
                    '<div class="layui-input-block">' .
                    '<input class="layui-input" name="config[' . $k . ']" value="' . $v['value'] . '">' .
                    '</div>' .
                    '</div>';
                break;
        }


    }
    return $config;
}


/**
 * @Notes:创建随机字符串
 * @User: chenping
 * @email: 375129701@qq.com
 * @param int $length
 * @return string
 */
function make_string($length = 8)
{
    // 密码字符集，可任意添加你需要的字符
    $chars = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
        'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
        't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
        'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',/* '!',
    '@','#', '$', '%', '^', '&', '*', '(', ')', '-', '_',
    '[', ']', '{', '}', '<', '>', '~', '`', '+', '=', ',',
    '.', ';', ':', '/', '?', '|'*/
    );
    // 在 $chars 中随机取 $length 个数组元素键名
    $keys = array_rand($chars, $length);
    $password = "";
    for ($i = 0; $i < $length; $i++) {
        // 将 $length 个数组元素连接成字符串
        $password .= $chars[$keys[$i]];
    }
    return $password;
}

//函数authcode($string, $operation, $key, $expiry)中的$string：字符串，明文或密文；$operation：DECODE表示解密，其它表示加密；$key：密匙；$expiry：密文有效期。
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
{
    // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
    $ckey_length = 4;
    // 密匙
    $key = md5($key ? $key : $GLOBALS['discuz_auth_key']);
    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) : substr(md5(microtime()), -$ckey_length)) : '';
    // 参与运算的密匙
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);
    // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
    //解密时会通过这个密匙验证数据完整性
    // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    // 产生密匙簿
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    // 核心加解密部分
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        // 从密匙簿得出密匙进行异或，再转成字符
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'DECODE') {
        // 验证数据有效性，请看未加密明文的格式
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}

/**
 * 获取毫秒级别的时间戳
 */
function getMsecTime()
{
    list($msec, $sec) = explode(' ', microtime());
    $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
    return $msectime;
}

/**
 * 毫秒转日期
 */
function getMsecToMescdate($msectime)
{
    $msectime = $msectime * 0.001;
    if (strstr($msectime, '.')) {
        sprintf("%01.3f", $msectime);
        list($usec, $sec) = explode(".", $msectime);
        $sec = str_pad($sec, 3, "0", STR_PAD_RIGHT);
    } else {
        $usec = $msectime;
        $sec = "000";
    }
    $date = date("Y-m-d H:i:s.x", $usec);
    return $mescdate = str_replace('x', $sec, $date);
}

/**
 * 日期转毫秒
 */
function getDateToMesc($mescdate)
{
    list($usec, $sec) = explode(".", $mescdate);
    $date = strtotime($usec);
    $return_data = str_pad($date . $sec, 13, "0", STR_PAD_RIGHT);
    return $msectime = $return_data;
}


//删除内容里的标签
function deleteHtml($str)
{
    $str = trim($str); //清除字符串两边的空格
    $str = strip_tags($str, ""); //利用php自带的函数清除html格式
    $str = preg_replace("/\t/", "", $str); //使用正则表达式替换内容，如：空格，换行，并将替换为空。
    $str = preg_replace("/\r\n/", "", $str);
    $str = preg_replace("/\r/", "", $str);
    $str = preg_replace("/\n/", "", $str);
    $str = preg_replace("/ /", "", $str);
    $str = preg_replace("/  /", "", $str);  //匹配html中的空格
    $str = preg_replace("/&nbsp;/", "", $str);  //匹配html中的空格
    return trim($str); //返回字符串
}

/**
 * @Notes:php把字符串变成数组(没有分隔符)
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $str
 * @return array
 */
function str($str)
{
    $arr = array();
    for ($i = 0; $i < mb_strlen($str, 'utf-8'); $i++) {
        $arr[$i] = mb_substr($str, $i, 1, 'utf-8');//mb_substr — 截取字符串,(PHP 4 >= 4.0.6, PHP 5, PHP 7)
    }
    return $arr;
}

/**
 * 获取文件传设置
 */
function get_upload_setting()
{
    $uploadSetting = get_option('upload_setting');
    if (empty($uploadSetting) || empty($uploadSetting['file_types'])) {
        $uploadSetting = [
            'file_types' => [
                'image' => [
                    'upload_max_filesize' => '10240',//单位KB
                    'extensions' => 'jpg,jpeg,png,gif,bmp4'
                ],
                'video' => [
                    'upload_max_filesize' => '10240',
                    'extensions' => 'mp4,avi,wmv,rm,rmvb,mkv'
                ],
                'audio' => [
                    'upload_max_filesize' => '10240',
                    'extensions' => 'mp3,wma,wav'
                ],
                'file' => [
                    'upload_max_filesize' => '10240',
                    'extensions' => 'txt,pdf,doc,docx,xls,xlsx,ppt,pptx,zip,rar'
                ]
            ],
            'chunk_size' => 512,//单位KB
            'max_files' => 20 //最大同时上传文件数
        ];
    }

    if (empty($uploadSetting['upload_max_filesize'])) {
        $uploadMaxFileSizeSetting = [];
        foreach ($uploadSetting['file_types'] as $setting) {
            $extensions = explode(',', trim($setting['extensions']));
            if (!empty($extensions)) {
                $uploadMaxFileSize = intval($setting['upload_max_filesize']) * 1024;//转化成B
                foreach ($extensions as $ext) {
                    if (!isset($uploadMaxFileSizeSetting[$ext]) || $uploadMaxFileSize > $uploadMaxFileSizeSetting[$ext]) {
                        $uploadMaxFileSizeSetting[$ext] = $uploadMaxFileSize;
                    }
                }
            }
        }
        $uploadSetting['upload_max_filesize'] = $uploadMaxFileSizeSetting;
    }
    return $uploadSetting;
}


/**
 * 获取文件扩展名
 * @param string $filename 文件名
 * @return string 文件扩展名
 */
function _get_file_extension($filename)
{
    $pathinfo = pathinfo($filename);
    return strtolower($pathinfo['extension']);
}

/**
 * 获取当前登录的管理员ID
 * @return int
 */
function _get_current_admin_id()
{
    $adminUser = cookie('adminUser');
    if (is_object(json_decode($adminUser))) {
        $adminUser = json_decode($adminUser, true);
    }
    if (is_array($adminUser)) {
        $adminUser = $adminUser;
    }
    if (is_string($adminUser)) {
        $adminUser = '';
    }
    return $adminUser['id'];
}

/**
 * 获取当前登录前台用户id
 * @return int
 */
function _get_current_user_id()
{
    $sessionUserId = session('user.id');
    if(!$sessionUserId)
    {
        $user = cookie("user");
        if(is_string($user)) $user = json_decode($user,true);
        $sessionUserId = $user['id'];
    }
    if (empty($sessionUserId)) {
        $user_id = request()->param("user_id");
        return $user_id?$user_id:0;
    }
    return $sessionUserId;
}

/**
 * 获取CMF系统的设置，此类设置用于全局
 * @param string $key 设置key，为空时返回所有配置信息
 * @return array|bool|mixed
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 */
function _get_cp_settings($key = "")
{
    $cmfSettings = cache("cp_settings");
    if (empty($cmfSettings)) {

        $objOptions = new \app\admin\model\system\Option();

        $objResult = $objOptions->where("option_name", 'system_setting')->find();

        $arrOption = $objResult ? $objResult->toArray() : [];

        if ($arrOption) {
            $cmfSettings = is_object($arrOption['option_value']) ? json_decode($arrOption['option_value'], true) : $arrOption;
        } else {
            $cmfSettings = [];
        }
        cache("cp_settings", $cmfSettings);
    }
    if (!empty($key)) {
        if (isset($cmfSettings[$key])) {
            return $cmfSettings[$key];
        } else {
            return false;
        }
    }
    return $cmfSettings;
}

/**
 * 获取插件配置
 * @param string $name 插件名，大驼峰格式
 * @return array
 */
function _get_plugin_config($name)
{
    $class = get_plugin_class($name);
    if (class_exists($class)) {
        $plugin = new $class();
        return $plugin->getConfig();
    } else {
        return [];
    }
}

/**
 * 返回带协议的域名
 */
function _get_domain()
{
    return request()->domain();
}

/**
 * 获取网站根目录
 * @return string 网站根目录
 */
function _get_root()
{
    $root = request()->root();
    $root = str_replace("//", '/', $root);
    $root = str_replace('/index.php', '', $root);

    if (defined('APP_NAMESPACE') && APP_NAMESPACE == 'api') {
        $root = preg_replace('/\/api(.php)$/', '', $root);
    }
    $root = rtrim($root, '/');
    return $root;
}

/**
 * 添加钩子,只执行一个
 * @param string $hook 钩子名称
 * @param mixed $params 传入参数
 * @return mixed
 */
function hook_one($hook, $params = null)
{
    return \think\facade\Hook::listen($hook, $params, true);
}


/**
 * 获取图片预览链接
 * @param string $file 文件路径，相对于upload
 * @param string $style 图片样式,支持各大云存储
 * @return string
 */
function _get_image_preview_url($file, $style = 'watermark')
{
    if (empty($file)) {
        return '';
    }

    if (strpos($file, "http") === 0) {
        return $file;
    } else if (strpos($file, "/") === 0) {
        return $file;
    } else {
//        $storage = cmf_get_option('storage');
//        if (empty($storage['type'])) {
//            $storage['type'] = 'Local';
//        }
//        if ($storage['type'] != 'Local') {
//            $watermark = cmf_get_plugin_config($storage['type']);
//            $style     = empty($style) ? $watermark['styles_watermark'] : $style;
//        }
        $storage = \app\common\lib\Storage::instance();
        return $storage->getPreviewUrl($file, $style);
        //云存储路径
        /*if(function_exists("getPreviewUrl"))
        {
        }else{
            return _get_domain().'/upload/'.$file;
        }*/
    }
}


/**
 * Notes:获取上传目录
 * User: chenping
 * email: 375129701@qq.com
 */
function getMikUpdir()
{
    $app = request()->param("app");
    if (!$app) {
        $app = 'default';
    }
    return $app . DIRECTORY_SEPARATOR . date("Ymd") . DIRECTORY_SEPARATOR;
}

/**
 * @Notes:获取文件加密方式 可以致辞云存储
 * @User: chenping
 * @email: 375129701@qq.com
 * @return string
 */
function getmd5File()
{
    // 基于以微秒计的当前时间，生成一个唯一的 ID。
    return md5(uniqid());
}


/**
 * 验证码检查，验证完后销毁验证码
 * @param string $value 要验证的字符串
 * @param string $id 验证码的ID
 * @param bool $reset 验证成功后是否重置
 * @return bool
 */
function cmf_captcha_check($value, $id = "", $reset = true)
{
    $captcha = new \think\captcha\Captcha();
    $captcha->reset = $reset;
    return $captcha->check($value, $id);
}

/**
 * 检查手机格式，中国手机不带国家代码，国际手机号格式为：国家代码-手机号
 * @param $mobile
 * @return bool
 */
function cmf_check_mobile($mobile)
{
    if (preg_match('/(^(13\d|14\d|15\d|16\d|17\d|18\d|19\d)\d{8})$/', $mobile)) {
        return true;
    } else {
        if (preg_match('/^\d{1,4}-\d{5,11}$/', $mobile)) {
            if (preg_match('/^\d{1,4}-0+/', $mobile)) {
                //不能以0开头
                return false;
            }
            return true;
        }
        return false;
    }
}

/**
 * CMF密码比较方法,所有涉及密码比较的地方都用这个方法
 * @param string $password 要比较的密码
 * @param string $passwordInDb 数据库保存的已经加密过的密码
 * @return boolean 密码相同，返回true
 */
function cmf_compare_password($password, $passwordInDb)
{
    if ($password != $passwordInDb) {
        return false;
    }
    return true;
}


/**
 * 生成用户 token
 * @param $userId
 * @param $deviceType
 * @return string 用户 token
 * @throws \think\Exception
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 * @throws \think\exception\PDOException
 */
function cmf_generate_user_token($userId, $deviceType)
{
    $userTokenQuery = \think\Db::name("user_token")
        ->where('user_id', $userId)
        ->where('device_type', $deviceType);
    $findUserToken = $userTokenQuery->find();
    $currentTime = time();
    $expireTime = $currentTime + 24 * 3600 * 180;
    $token = md5(uniqid()) . md5(uniqid());
    if (empty($findUserToken)) {
        \think\Db::name("user_token")->insert([
            'token' => $token,
            'user_id' => $userId,
            'expire_time' => $expireTime,
            'create_time' => $currentTime,
            'device_type' => $deviceType
        ]);
    } else {
        if ($findUserToken['expire_time'] > time() && !empty($findUserToken['token'])) {
            $token = $findUserToken['token'];
        } else {
            \think\Db::name("user_token")
                ->where('user_id', $userId)
                ->where('device_type', $deviceType)
                ->update([
                    'token' => $token,
                    'expire_time' => $expireTime,
                    'create_time' => $currentTime
                ]);
        }

    }
    return $token;
}

/**
 * 获取客户端IP地址
 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
 * @param boolean $adv 是否进行高级模式获取（有可能被伪装）
 * @return string
 */
function get_client_ip($type = 0, $adv = true)
{
    return request()->ip($type, $adv);
}


/**
 * 获取文件下载地址
 * @param string $file 文件路径，相对于upload
 * @param string $loca 下载到本地
 * @return string
 */
function _download_file_download($file, $loca = false)
{
    $storage = get_option('storage');
    if (empty($storage['type']) || $storage['type']=='Local')
    {

        if (file_exists(dirname(app_path()) . '/public/upload/' . $file))
        {
            $ext = pathinfo($file);
            return download("upload/" . $file, $ext['basename']);
        }
    }
    if ($storage['type'] != 'Local')
    {
        $storage = \app\common\lib\Storage::instance();
        return $storage->downloadFile(_get_image_preview_url($file), $loca);
    }
    return "error";
}


/**
 * @Notes:获取插件设置项
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $name
 * @return mixed
 */
function _get_plugin_setting($name)
{
    $config = \think\Db::name('plugin')->where('name', $name)->value('config');

    if (!empty($config) && $config != "null") {
        $config = json_decode($config, true);
    }
    return $config;
}

/**
 * @deprecated
 * 判读是否sae环境
 * @return bool
 */
function cmf_is_sae()
{
    if (function_exists('saeAutoLoader')) {
        return true;
    } else {
        return false;
    }
}

/**
 * 获取网站根目录
 * @return string 网站根目录
 */
function cmf_get_root()
{
    $root = request()->root();
    $root = str_replace("//", '/', $root);
    $root = str_replace('/index.php', '', $root);
    if (defined('APP_NAMESPACE') && APP_NAMESPACE == 'api') {
        $root = preg_replace('/\/api(.php)$/', '', $root);
    }
    $root = rtrim($root, '/');
    return $root;
}

/**
 * @Notes:excel 文件导出方法
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $data
 * @param array $header
 * @param $fileName
 * @return bool
 */
function importExcel($data, $header = [], $fileName)
{
    if (!$data) return false;
    if (!$header) return false;
    if (!$fileName) $fileName = time();

    $spreadsheet = new PhpOffice\PhpSpreadsheet\Spreadsheet();
    $workSheet = $spreadsheet->getActiveSheet();
    $workSheet->setTitle('工作表格');

    //设置单元格表头内容
    foreach (array_values($header) as $key => $value)
    {
        $workSheet->setCellValueByColumnAndRow($key + 1, 1, $value);
    }
    //从第二行开始
    $row = 2;
    foreach ($data as $item)
    {
        foreach ($item as $key=>$value)
        {
            if(in_array($key,array_keys($header)))
            {
                $workSheet->setCellValueByColumnAndRow(array_search($key,array_keys($header))+1, $row, $value);
            }
        }
        $row++;
    }
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header("Content-Disposition: attachment;filename={$fileName}.xlsx");
    header('Cache-Control: max-age=0');
    header('Cache-Control: cache, must-revalidate');
    //输出到浏览器
    $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
    $writer->save('php://output');
    $spreadsheet->disconnectWorksheets();
    unset($spreadsheet);
    // PHPExecl下载并解决打开execl出现部分内容有问题是否让我们尽量尝试恢复的问题 在后面添加 die 即可解决问题
    die;
}

/**
 * @Notes:生成pdf 文件
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $title 文件标题
 * @param $content 文件生容
 * @param string $fileName 文件发名称
 * @param string $logo 水印
 * @param string $header 页眉
 * @param string $footer 页脚
 * @return string
 */
function importPdf($title,$content,$fileName='',$logo='',$header='',$footer='')
{
    $defaultConfig = (new Mpdf\Config\ConfigVariables())->getDefaults();
    $fontDirs = $defaultConfig['fontDir'];
    $defaultFontConfig = (new Mpdf\Config\FontVariables())->getDefaults();
    $fontData = $defaultFontConfig['fontdata'];
    $mpdf = new \Mpdf\Mpdf([
        'fontDir' => array_merge($fontDirs, [
           'dompdf_font/',
        ]),
        'format' => [190, 236],
        'fontdata' => $fontData + [
                'frutiger' => [
                    'R' => 'simsun.ttf',
                    'I' => 'simsun.ttf',
                ]
            ],
        'default_font' => 'frutiger',
        'tempDir' => dirname(WEB_ROOT) . '/runtime/pdf',
    ]);

    //设置主题
    $mpdf->SetSubject($title);
    $mpdf->SetAuthor(isset($data['user']['username'])?$data['user']['username']:'');
    //设置页眉页脚
    $mpdf->SetHTMLFooter($footer);
    $mpdf->SetHTMLHeader($header);

    //设置水印图像
    $mpdf->SetWatermarkImage($logo,0.2,"D");

    $mpdf->Image($logo, 0, 0, 150, 60, 'png', '', true, false);

    $mpdf->showImageErrors = true;
    $mpdf->showWatermarkImage = true;

    /**
     * 日志设置
     */
    $logDir = dirname(WEB_ROOT) . '/runtime/log/'.date("Ym",time()).'/'.date("d").'mpdf.log';
    $logger = new \Monolog\Logger('mpdf');
    $logger->pushHandler(new \Monolog\Handler\StreamHandler($logDir, \Monolog\Logger::DEBUG));
    $mpdf->setLogger($logger);

    $mpdf->WriteHTML($content);
    header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
    header('Content-Disposition: attachment;filename="'.($title?$title:$fileName).'.pdf"');
    header('Cache-Control: max-age=0');
    // If you're serving to IE 9, then the following may be needed
    header('Cache-Control: max-age=1');
    // If you're serving to IE over SSL, then the following may be needed
    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
    header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
    header('Pragma: public'); // HTTP/1.0
    $mpdf->Output("php://output");
    exit;

    $html = '<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <style type="text/css">
  /*  @font-face {
          font-family: "simsun";
          src: url("http://tp51admin:9503/dompdf_font/simsun.ttf") format ("truetype");
        }*/
        *{
            font-family:DejaVu Sans !important;
        }
    </style>
</head>
<body style="font-family: simsun !important;">'.
        $content.
        '</body>
</html>';
    /*$dompdf = new \Dompdf\Dompdf();
    $dompdf->load_html($html , 'UTF-8');
    $dompdf->render();
    $dompdf->stream($fileName.'.pdf');*/
    //return $dompdf->output();
    //exit;

    define("K_PATH_IMAGES",'');

    $pdf  = new \app\common\lib\Pdf(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT,true, 'UTF-8', false);
    /**
     * 设置文件信息
     */
    $pdf->SetCreator(PDF_CREATOR);
    $pdf->SetAuthor(isset($data['user']['username'])?$data['user']['username']:'');
    $pdf->SetTitle($title);
    $pdf->SetKeywords($title);
    $pdf->SetSubject($title);

    /**
     * 设置页眉页脚
     */
    $pdf->SetHeaderData($logo, 30, $header, $footer, array(0,64,255), array(0,64,128));
    $pdf->setHeaderFont(array('stsongstdlight', '', '10'));
    $pdf->setFooterFont(array('stsongstdlight', '', '10'));


    /**
     * 设置文档对齐，间距，字体，图片
     */
    $pdf->SetCreator(PDF_CREATOR);
    $pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
    $pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);

    /**
     * 设置页眉页脚 边距
     */
    $pdf->setHeaderMargin(PDF_MARGIN_HEADER);
    $pdf->setFooterMargin(PDF_MARGIN_FOOTER);

    /**
     *自动分页
     */
    $pdf->SetAutoPageBreak(true, PDF_MARGIN_BOTTOM);
    $pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
    $pdf->setFontSubsetting(true);

    /**
     * 设置正文字体，大小   （stsongstdlight，这个字体支持的文字更全，支持中文不乱码）
     */
    $pdf->SetFont('stsongstdlight', '', 14);


    /**
     * 创建页面，渲染PDF
     */
    $pdf->AddPage();
    $pdf->setPageMark();
    /**
     * 设置水印
     */
    if($logo)
    {
        $pdf->Image($logo, 100, 100, 100, 100, '', 'http://www.xgzrs.com/', '', false, 300);
    }
    $pdf->writeHTML($content, true, 0, true, 0);

    $pdf->lastPage();



    return $pdf->Output($fileName.".pdf", 'D');
}

/**
 * @Notes:导出文档
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $filename
 * @param $data
 * @param string $login
 */
function importWord($filename,$data,$logo="")
{
    $content = '<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
</head>
<body >'.
        $data.
        '</body>
</html>';

    header("Cache-Control: no-cache, must-revalidate");
    header("Pragma: no-cache");
    $fileContent = getWordDocument($content,'',false);
    $fileName = iconv("utf-8", "GBK", 'jb51' . '_'. $filename . '_' . rand(100, 999));
    header("Content-Type: application/doc");
    header("Content-Disposition: attachment; filename=" . $fileName . ".doc");
    echo $fileContent;
    /*$word = new \app\common\lib\PHPWordLib([
        "fileName" => $filename
    ]);
    $word->SetWordData($data);
    $word->createServer();*/
}


/**
 * 根据HTML代码获取word文档内容
 * 创建一个本质为mht的文档，该函数会分析文件内容并从远程下载页面中的图片资源
 * 该函数依赖于类MhtFileMaker
 * 该函数会分析img标签，提取src的属性值。但是，src的属性值必须被引号包围，否则不能提取
 *
 * @param string $content HTML内容
 * @param string $absolutePath 网页的绝对路径。如果HTML内容里的图片路径为相对路径，那么就需要填写这个参数，来让该函数自动填补成绝对路径。这个参数最后需要以/结束
 * @param bool $isEraseLink 是否去掉HTML内容中的链接
 */
function getWordDocument( $content , $absolutePath = "" , $isEraseLink = true )
{
    $mht = new \app\common\lib\MhtFileMaker();
    if ($isEraseLink) $content = preg_replace('/<a\s*.*?\s*>(\s*.*?\s*)<\/a>/i' , '$1' , $content); //去掉链接

    $images = array();
    $files = array();
    $matches = array();
    //这个算法要求src后的属性值必须使用引号括起来
    if ( preg_match_all('/<img[.\n]*?src\s*?=\s*?[\"\'](.*?)[\"\'](.*?)\/>/i',$content ,$matches ) )
    {
        $arrPath = $matches[1];
        for ( $i=0;$i<count($arrPath);$i++)
        {
            $path = $arrPath[$i];
            $imgPath = trim( $path );
            if ( $imgPath != "" )
            {
                $files[] = $imgPath;
                if( substr($imgPath,0,7) == 'http://')
                {
                    //绝对链接，不加前缀
                }
                else
                {
                    $imgPath = $absolutePath.$imgPath;
                }
                $images[] = $imgPath;
            }
        }
    }
    $mht->AddContents("tmp.html",$mht->GetMimeType("tmp.html"),$content);
    for ( $i=0;$i<count($images);$i++)
    {
        $image = $images[$i];
        if ( @fopen($image , 'r') )
        {
            $imgcontent = @file_get_contents( $image );
            if ( $content )
                $mht->AddContents($files[$i],$mht->GetMimeType($image),$imgcontent);
        }
        else
        {
            echo "file:".$image." not exist!<br />";
        }
    }

    return $mht->GetFile();
}


/**
 * 替换编辑器内容中的文件地址
 * @param string  $content     编辑器内容
 * @param boolean $isForDbSave true:表示把绝对地址换成相对地址,用于数据库保存,false:表示把相对地址换成绝对地址用于界面显示
 * @return string
 */
function cmf_replace_content_file_url($content, $isForDbSave = false)
{
    $content = str_replace("<img","<img style='max-width:100%'",$content);
    //import('phpQuery.phpQuery', EXTEND_PATH);
    \phpQuery::newDocumentHTML($content);
    $pq = pq(null);

    $storage       = \app\common\lib\Storage::instance();
    $localStorage  = new \app\common\lib\storage\Local([]);
    //$storageDomain = $storage->getDomain();
    $storageDomain = str_replace(["https://","http://"],"", $storage->getDomain());
    $domain        = request()->host();

    $images = $pq->find("img");
    if ($images->length) {
        foreach ($images as $img) {
            $img    = pq($img);
            $imgSrc = $img->attr("src");
            if ($isForDbSave) {
                if (preg_match("/^\/upload\//", $imgSrc))
                {
                    $img->attr("src", preg_replace("/^\/upload\//", '', $imgSrc));
                } elseif (preg_match("/^http(s)?:\/\/$domain\/upload\//", $imgSrc))
                {
                    $img->attr("src", $localStorage->getFilePath($imgSrc));
                }elseif (preg_match("/^http(s)?:\/\/$storageDomain\//", $imgSrc))
                {
                    $img->attr("src", $storage->getFilePath($imgSrc));
                }
            } else {
                $img->attr("src", cmf_get_image_url($imgSrc));
            }

        }
    }



    $links = $pq->find("a");
    if ($links->length) {
        foreach ($links as $link) {
            $link = pq($link);
            $href = $link->attr("href");

            if ($isForDbSave) {
                if (preg_match("/^\/upload\//", $href)) {
                    $link->attr("href", preg_replace("/^\/upload\//", '', $href));
                } elseif (preg_match("/^http(s)?:\/\/$domain\/upload\//", $href)) {
                    $link->attr("href", $localStorage->getFilePath($href));
                } elseif (preg_match("/^http(s)?:\/\/$storageDomain\//", $href)) {
                    $link->attr("href", $storage->getFilePath($href));
                }

            } else {
                if (!(preg_match("/^\//", $href) || preg_match("/^http/", $href))) {
                    $link->attr("href", cmf_get_file_download_url($href));
                }

            }

        }
    }
    $content = $pq->html();
    \phpQuery::$documents = null;
    return $content;
}

/**
 * 转化数据库保存图片的文件路径，为可以访问的url
 * @param string $file  文件路径，数据存储的文件相对路径
 * @param string $style 图片样式,支持各大云存储
 * @return string 图片链接
 */
function cmf_get_image_url($file, $style = 'watermark')
{
    if (empty($file)) {
        return '';
    }

    if (strpos($file, "http") === 0) {
        return $file;
    } else if (strpos($file, "/") === 0) {
        return cmf_get_domain() . $file;
    } else {
//        $storage = cmf_get_option('storage');
//        if (empty($storage['type'])) {
//            $storage['type'] = 'Local';
//        }
//        if ($storage['type'] != 'Local') {
//            $watermark = cmf_get_plugin_config($storage['type']);
//            $style     = empty($style) ? $watermark['styles_watermark'] : $style;
//        }
        $storage = \app\common\lib\Storage::instance();
        return $storage->getImageUrl($file, $style);
    }
}

/**
 * 返回带协议的域名
 */
function cmf_get_domain()
{
    return request()->domain();
}

/**
 * 获取用户设置的配置项
 * @param string $key 配置键值,都小写
 * @param int $userId 用户在数据库唯一值
 * @return array
 */
if (!function_exists("get_user_option"))
{
    function get_user_option($key,$userId)
    {
        if (!is_string($key) || empty($key))
        {
            return [];
        }

        if (PHP_SAPI != 'cli')
        {
            static $cmfGetOption;

            if (empty($cmfGetOption))
            {
                $cmfGetOption = [];
            } else {
                if (!empty($cmfGetOption[$key]))
                {
                    return $cmfGetOption[$key];
                }
            }
        }
        $optionValue = cache("user_options_{$userId}_" . $key);
        if (empty($optionValue))
        {
            $optionValue = \think\Db::name('user_option')->where('option_name', $key)
                ->where("user_id",$userId)
                ->value('option_value');
            if (!empty($optionValue))
            {
                $optionValue = json_decode($optionValue, true);
                cache("user_options_{$userId}_" . $key, $optionValue);
            }
        }
        $cmfGetOption[$key] = $optionValue;
        return $optionValue;
    }

}

/**
 * 用户设置配置方法实现
 * @param string $key 配置键值,都小写
 * @param int $userId 用户在数据库的唯一值
 * @param array $data 配置值，数组
 * @param bool $replace 是否完全替换
 * @return bool 是否成功
 * @throws \think\Exception
 * @throws \think\db\exception\DataNotFoundException
 * @throws \think\db\exception\ModelNotFoundException
 * @throws \think\exception\DbException
 * @throws \think\exception\PDOException
 */
function set_user_option($key, $data,$userId, $replace = false,$delete)
{
    if (!is_array($data) || empty($data) || !is_string($key) || empty($key))
    {
        return false;
    }

    $key = strtolower($key);
    $option = [];
    $findOption = \think\Db::name('user_option')->where('option_name', $key)
        ->where("user_id",$userId)
        ->find();

    if ($findOption)
    {
        if (!$replace)
        {
            $oldOptionValue = json_decode($findOption['option_value'], true);
            if (!empty($oldOptionValue))
            {
                if (!empty($oldOptionValue))
                {
                    $data = array_merge($oldOptionValue, $data);
                    if (count($oldOptionValue) != count($oldOptionValue, 1) && count($data)!=count($data,1))
                    {
                        $data = second_array_unique_bykey($data,"id");
                    }
                }
            }
        }
        //删除操作
        if($delete)
        {
            foreach ($data as $k=>$v)
            {
                if($v['id']==$delete['id'] && $v['name']==$delete['name'])
                {
                    unset($data[$k]);
                }
            }
        }
        $option['option_value'] = json_encode($data);
        \think\Db::name('user_option')->where('option_name', $key)
            ->where("user_id",$userId)
            ->update($option);
    } else {
        $option['option_name'] = $key;
        $option['option_value'] = json_encode($data);
        $option['user_id'] = $userId;

        \think\Db::name('user_option')->insert($option);
    }

    cache("user_options_{$userId}" . $key, null);

    return true;
}

/**
 * 获取文件下载链接
 * @param string $file    文件路径，数据库里保存的相对路径
 * @param int    $expires 过期时间，单位 s
 * @return string 文件链接
 */
function cmf_get_file_download_url($file, $expires = 3600)
{
    if (empty($file))
    {
        return '';
    }
    if (strpos($file, "http") === 0) {
        return $file;
    } else if (strpos($file, "/") === 0) {
        return $file;
    } else if(strpos($file, "#") === 0) {
        return $file;
    } else {
        $storage = \app\common\lib\Storage::instance();
        return $storage->getFileDownloadUrl($file, $expires);
    }
}


/**
 * @Notes:pdf 文件转 html 文档
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $pdfFile
 * @param int $page
 * @return string
 */
function pdfParser($pdfFile,$page=-1)
{
    $parser = new \Smalot\PdfParser\Parser();
    $pdf    = $parser->parseFile($pdfFile);
    if($page===0){
        $pages  = $pdf->getPages();
        return $pages[$page]->$pdf();
    }else{
        return $pdf->getText();
    }
}


/**
 * @Notes:
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $filename 文件名
 * @param string $f 自定义深沉的文件名
 */
function wordParser($filename,$f='')
{
    $fileParser = pathinfo($filename);
    $phpWord = \PhpOffice\PhpWord\IOFactory::load($filename);
    $xmlWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, "HTML");
    $path = dirname(WEB_ROOT).DIRECTORY_SEPARATOR.'resources'.DIRECTORY_SEPARATOR;
    $file = $f?$f:$fileParser['filename'].'.html';
    $xmlWriter->save($path.$file);
    return $path.$file;
}


/**
 * @Notes:word 文件在线预览
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $filename
 */
function wordView($filename,$isJump=false)
{
    $ext =  pathinfo($filename);
    if(isset($ext['extension']) && $ext['extension']=='doc' || $ext['extension']=='docx' || $ext['extension']=='xls'||$ext['extension']=='xlsx')
    {
        if($isJump)
        {
            header('Location: https://view.officeapps.live.com/op/view.aspx?src='.$filename);
        }else{
            return "https://view.officeapps.live.com/op/view.aspx?src=".$filename;
        }
    }else{
        return false;
    }
}

/**
 * @Notes:pdf 文件预览
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $filename
 * @return bool
 */
function pdfView($filename)
{
    $ext =  pathinfo($filename);
    if(isset($ext['extension']) && $ext['extension']=='pdf' )
    {
        header('Location:'.$filename);
    }else{
        return false;
    }
}

/**
 * @Notes:递归目录创建
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $dir
 * @return bool
 */
function mkDirs($dir){
    if(!is_dir($dir)){
        if(!mkDirs(dirname($dir))){
            return false;
        }
        if(!mkdir($dir,0777)){
            return false;
        }
    }
    return true;
}

/**
 *
 * 基于php 扩展：imagick 实现的图pdf 文件转图片 imagick 需要ghostscript 的支持
 * PDF2PNG
 * @param $pdf  待处理的PDF文件
 * @param $path 待保存的图片路径
 * @param $page 待导出的页面 -1为全部 0为第一页 1为第二页
 * @return      保存好的图片路径和文件名
 */
function pdf2png($pdf,$path="download/pdf/img",$page=-1,$type='png')
{
    if(!extension_loaded('imagick'))
    {
        return false;
    }

    $im = new Imagick();
    $im->setResolution(120,120);
    $im->setCompressionQuality(100);


    //$content = file_get_contents($pdf);

    if($page==-1)
    {
        $im->readImage($pdf);
        //$im->readImageBlob($content);
    } else{
        //$im->readImageBlob($content);
        $im->readImage($pdf."[".$page."]");
    }

    $Return =[];
    foreach ($im as $Key => $Var)
    {
        $Var->setImageFormat($type);
        $filename = $path."/". md5($Key.time()).'.'.$type;
        if($Var->writeImage($filename) == true)
        {
            $Return[] = $filename;
        }
    }
    return $Return;
}

/**
 * 寻找所有子级元素
 * @param int $pid
 * @param int $lev
 * @param $descendant
 * @return array
 */

function findChild($pid = 0, $lev=1, $descendant)
{
    static $child=array();
    foreach($descendant as $v){
        if($v["pid"]==$pid){
            $v["lev"]=$lev;
            $child[]=$v;
            findChild($v["id"],$lev+1,$descendant);
        }
    }
    return $child;
}
/**
 * 寻找所有父级元素
 * @param $id
 * @param $ancestor
 * @return array
 */
function findParent($id, $ancestor)
{
    static $parent=array();
    $idlist = array_column($parent,'id');
    foreach($ancestor as $v){
        //从小到大 排列
        if($v["id"]==$id and !in_array($v['id'],$idlist)){
            $parent[]=$v;
            if($v["pid"] > 0){
                findParent($v["pid"],$ancestor);
            }
        }
    }
    return $parent;
}

/**
 * 将数据格式化成树形结构
 * @param array $data
 * @return array
 */
function generateTree($data) {
    //注意如果你的数组下标默认是0的话，那就要处理一下数组 首先将下标设置为ID
    foreach ($data as $v) $data[$v['id']] = $v; unset($data[0]);
    foreach ($data as $v)
        $data[$v['pid']]['lower'][$v['id']] = &$data[$v['id']];
    return isset($data[0]['lower']) ? $data[0]['lower'] : array();
}

/**
 * @Notes:无限极分类数据
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $data
 * @param int $pid
 * @return array
 */
function Tree($data , $pid=0){
    $arr = [];
    foreach ($data as $k=>$v){
        if($pid==$v['pid']){
            $v['child'] = Tree($data,$v['id']);
            $arr[] = $v;
        }
    }
    return $arr;
}


/**
 * 获取当前登录的前台用户的信息，未登录时，返回false
 * @return array|boolean
 */
function _get_current_user()
{
    $sessionUser = session('user');
    if(!$sessionUser) $sessionUser = cookie("user");
    if(is_string($sessionUser)) $sessionUser = json_decode($sessionUser,true);
    if (!empty($sessionUser)) {
        unset($sessionUser['password']); // 销毁敏感数据
        return $sessionUser;
    } else {
        return false;
    }
}

/**
 * 判断前台用户是否登录
 * @return boolean
 */
/**
 * 判断前台用户是否登录
 * @return boolean
 */
function _is_user_login()
{
    $sessionUser = session('user');
    if(!$sessionUser) $sessionUser = cookie("user");
    if(is_string($sessionUser)) $sessionUser = json_decode($sessionUser,true);
    return !empty($sessionUser);
}


/**
 * 字符传替换
 * @param $str 字符串
 * @param $start 替换字符的开始文字
 * @param $len  替换字符的长度
 * @param $symbol 替换的字符  例如*、#等
 * @return string
 */
function str_rep($str, $start, $len, $symbol = '*')
{
    $end = $start + $len;
    // 截取头保留的字符
    $str1 = mb_substr($str, 0, $start);
    // 截取尾保留的字符
    $str2 = mb_substr($str, $end);
    //  生产要替换的字符
    $symbol_num = '';
    for ($i = 0; $i < 3; $i++) {
        $symbol_num .= $symbol;
    }
    return $str1 . $symbol_num . $str2;
}


/**
 * @Notes：计算时间段
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $date
 * @return false|string
 */
function dateline($date)
{
    $n = time();
    $t = $n - $date;
    $m = 86400*30;
    if($t <= 3600){
        return ceil($t/60).'分钟前';
    }else if($t >3600 && $t<86400){
        return ceil($t/3600).'小时前';
    }else if( $t >86400 && $t < $m){
        return ceil($t/86400).'天前';
    }else{
        return date("Y-m-d",$date);
    }
}


/**
 * @Notes:获取本站用户，以及绑定的第三方用户
 * @User: chenping
 * @email: 375129701@qq.com
 * @return array
 */
function get_weUser_thirdUser()
{
    $user = _get_current_user();
    $web_user = [];
    $third_user = [];
    if(isset($user['unionid']) && !empty($user['unionid']))
    {
        $third_user = \app\admin\model\user\AdminOauth::where("union_id",$user['unionid'])->find();
        $web_user = \app\admin\model\user\User::where("id",$third_user['user_id'])->find();

    }elseif(isset($user['id']) && !empty($user['id']))
    {
        $web_user   =\app\admin\model\user\User::where("id",$user['id'])->find();;
        $third_user = \app\admin\model\user\AdminOauth::where("user_id",$user['id'])->find();
    }
    return [
        "web_user"   => $web_user,
        "third_user" => $third_user
    ];
}


/**
 * @Notes:判断是本站用户，还是第三方用户，并返回当前id
 * @User: chenping
 * @email: 375129701@qq.com
 * @return array
 */
function is_web_third()
{
    $user_id = '';
    $is_third ='';
    $user  = get_weUser_thirdUser();
    if(!empty($user['web_user']) && isset($user['web_user']['id']) && $user['web_user']['id']>0)
    {
        $user_id  = $user['web_user']['id'];
        $is_third = 1;
    }elseif(!empty($user['third_user']) && isset($user['third_user']['id']) && $user['third_user']['id']>0){
        $user_id  = $user['third_user']['id'];
        $is_third = 0;
    }
    return [
        "user_id" => $user_id,
        "is_third" => $is_third
    ];
}

/**
 * @Notes:远程文件下载
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $url
 * @param string $file
 * @param int $timeout
 * @return bool|mixed|string
 */
function download_remote_file($url, $file="", $timeout=60) {
    $file = empty($file) ? pathinfo($url,PATHINFO_BASENAME) : $file;
    $dir = pathinfo($file,PATHINFO_DIRNAME);
    !is_dir($dir) && @mkdir($dir,0755,true);
    $url = str_replace(" ","%20",$url);

    if(function_exists('curl_init')) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        $temp = curl_exec($ch);
        if(@file_put_contents($file, $temp) && !curl_error($ch)) {
            return $file;
        } else {
            return false;
        }
    } else {
        $opts = array(
            "http"=>array(
                "method"=>"GET",
                "header"=>"",
                "timeout"=>$timeout)
        );
        $context = stream_context_create($opts);
        if(@copy($url, $file, $context)) {
            //$http_response_header
            return $file;
        } else {
            return false;
        }
    }
}


/**
 * @Notes:生辰二维码类型
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $data
 * @return \chillerlan\QRCode\QRCode
 */
function qrcode($data)
{
     return (new \chillerlan\QRCode\QRCode())->render($data);
}


/**
 * @Notes:php 读取pdf文件页数
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $pdfname
 * @return int
 */
function count_pages($pdfname)
{
    $pdftext = file_get_contents($pdfname);
    $num = preg_match_all("/\/Page\W/", $pdftext, $dummy);
    return $num;
}


/**
 * @Notes:扫码关注登录
 * @User: chenping
 * @email: 375129701@qq.com
 * @return bool
 */
function is_mobile()
{
    // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
    if (isset ($_SERVER['HTTP_X_WAP_PROFILE']))
    {
        return true;
    }
    // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
    if (isset ($_SERVER['HTTP_VIA'])) {
        return stristr($_SERVER['HTTP_VIA'], "wap") ? true : false;// 找不到为flase,否则为TRUE
    }
    // 判断手机发送的客户端标志,兼容性有待提高
    if (isset ($_SERVER['HTTP_USER_AGENT'])) {
        $clientkeywords = array(
            'mobile',
            'nokia',
            'sony',
            'ericsson',
            'mot',
            'samsung',
            'htc',
            'sgh',
            'lg',
            'sharp',
            'sie-',
            'philips',
            'panasonic',
            'alcatel',
            'lenovo',
            'iphone',
            'ipod',
            'blackberry',
            'meizu',
            'android',
            'netfront',
            'symbian',
            'ucweb',
            'windowsce',
            'palm',
            'operamini',
            'operamobi',
            'openwave',
            'nexusone',
            'cldc',
            'midp',
            'wap'
        );
        // 从HTTP_USER_AGENT中查找手机浏览器的关键字
        if (preg_match("/(" . implode('|', $clientkeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
            return true;
        }
    }
    // 协议法，因为有可能不准确，放到最后判断
    if (isset ($_SERVER['HTTP_ACCEPT'])) {
        // 如果只支持wml并且不支持html那一定是移动设备
        // 如果支持wml和html但是wml在html之前则是移动设备
        if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
            return true;
        }// /PayCallback/unifiedorder
    }
    return false;
}



/**
 * 判断是否微信内置浏览器访问
 * @return bool
 */
function isWxClient()
{
    return strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false;
}

/**
 * @Notes:文件下载
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $file
 * @return string
 */
function download_file($file,$loca=false)
{
    if (empty($file))
    {
        return '';
    }
    if (strpos($file, "http") === 0) {
        return $file;
    } else if (strpos($file, "/") === 0) {
        return $file;
    } else if(strpos($file, "#") === 0) {
        return $file;
    } else {
        $storage = \app\common\lib\Storage::instance();
        return $storage->downloadFile($file, $loca);
    }
}

/**
 * @Notes:根据秒数变成小时，分钟，秒
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $time
 * @return bool|string
 */
function Sec2Time($time){
    if(is_numeric($time)){
        $value = array(
            "years" => 0, "days" => 0, "hours" => 0,
            "minutes" => 0, "seconds" => 0,
        );
        if($time >= 31556926){
            $value["years"] = floor($time/31556926);
            $time = ($time%31556926);
        }
        if($time >= 86400){
            $value["days"] = floor($time/86400);
            $time = ($time%86400);
        }
        if($time >= 3600){
            $value["hours"] = floor($time/3600);
            $time = ($time%3600);
        }
        if($time >= 60){
            $value["minutes"] = floor($time/60);
            $time = ($time%60);
        }
        $value["seconds"] = floor($time);
        //return (array) $value;
        $t="";
        if(!empty($value['years'])){
            $t.=$value["years"] ."年";
        }
        if(!empty($value["days"])){
            $t.=$value['days']."天";
        }
        if(!empty($value["hours"])){
            $t.=$value['hours']."小时";
        }
        if(!empty($value["minutes"])){
            $t.=$value['minutes']."分";
        }
        $t.=$value["seconds"]."秒";
        // $t=$value["years"] ."年". $value["days"] ."天"." ". $value["hours"] ."小时". $value["minutes"] ."分".$value["seconds"]."秒";
        return $t;
    }else{
        return (bool) FALSE;
    }
}
/**
 * @Notes:二维数去重
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $arr
 * @param $key
 * @return mixed
 */
function second_array_unique_bykey($arr, $key){
    $tmp_arr = array();
    foreach($arr as $k => $v)
    {
        if($v)
        {
            if(in_array($v[$key], $tmp_arr))   //搜索$v[$key]是否在$tmp_arr数组中存在，若存在返回true
            {
                unset($arr[$k]); //销毁一个变量  如果$tmp_arr中已存在相同的值就删除该值
            }
            else {
                $tmp_arr[$k] = $v[$key];  //将不同的值放在该数组中保存
            }
        }else{
            unset($arr[$k]);
        }
    }
    //ksort($arr); //ksort函数对数组进行排序(保留原键值key)  sort为不保留key值
    sort($arr);
    return $arr;
}
/**
 * @Notes: 字母按顺排序
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $letter
 * @return string
 */
function letter_sort($letter)
{
    if(!preg_match('/[\x{4e00}-\x{9fa5}]/u', $letter))
    {
        $arr = str_split($letter);
        sort($arr);
        $abc = implode($arr,',');
        return $abc;
    }else{
        return $letter;
    }
}


/**
 * @Notes:分段式上传
 * @User: chenping
 * @email: 375129701@qq.com
 * @return \think\response\Json
 */
function chunkUploadFile($dir='')
{
    header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    header("Cache-Control: no-store, no-cache, must-revalidate");
    header("Cache-Control: post-check=0, pre-check=0", false);
    header("Access-Control-Allow-Origin: *"); // Support CORS
    header("Pragma: no-cache");
    $folder = $dir;
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        exit; // finish preflight CORS requests here
    }
    if ( !empty($_REQUEST[ 'debug' ]) ) {
        $random = rand(0, intval($_REQUEST[ 'debug' ]) );
        if ( $random === 0 ) {
            header("HTTP/1.0 500 Internal Server Error");
            exit;
        }
    }
    // header("HTTP/1.0 500 Internal Server Error");
    // exit;
    // 5 minutes execution time
    set_time_limit(24 * 60 * 60);
    // Uncomment this one to fake upload time
    usleep(5000);
    // Settings
    $targetDir = './upload'.DIRECTORY_SEPARATOR.'file_material_tmp';            //存放分片临时目录
    if($folder){
        $uploadDir = './upload'.DIRECTORY_SEPARATOR.'file_material'.$folder.DIRECTORY_SEPARATOR.date('Ymd');
    }else{
        $uploadDir = './upload'.DIRECTORY_SEPARATOR.'file_material'.DIRECTORY_SEPARATOR.date('Ymd');    //分片合并存放目录
    }

    $cleanupTargetDir = true; // Remove old files
    $maxFileAge = 5 * 3600; // Temp file age in seconds

    // Create target dir
    if (!file_exists($targetDir)) {
        mkdir($targetDir,0777,true);
    }
    // Create target dir
    if (!file_exists($uploadDir)) {
        mkdir($uploadDir,0777,true);
    }
    // Get a file name
    if (isset($_REQUEST["name"])) {
        $fileName = $_REQUEST["name"];
    } elseif (!empty($_FILES)) {
        $fileName = $_FILES["file"]["name"];
    } else {
        $fileName = uniqid("file_");
    }
    $oldName = $fileName;

    $fileName = iconv('UTF-8','gb2312',$fileName);
    $filePath = $targetDir . DIRECTORY_SEPARATOR . $fileName;
    // $uploadPath = $uploadDir . DIRECTORY_SEPARATOR . $fileName;
    // Chunking might be enabled
    $chunk = isset($_REQUEST["chunk"]) ? intval($_REQUEST["chunk"]) : 0;
    $chunks = isset($_REQUEST["chunks"]) ? intval($_REQUEST["chunks"]) : 1;
    // Remove old temp files
    if ($cleanupTargetDir) {
        if (!is_dir($targetDir) || !$dir = opendir($targetDir)) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 100, "message": "Failed to open temp directory111."}, "id" : "id"}');
        }
        while (($file = readdir($dir)) !== false) {
            $tmpfilePath = $targetDir . DIRECTORY_SEPARATOR . $file;
            // If temp file is current file proceed to the next
            if ($tmpfilePath == "{$filePath}_{$chunk}.part" || $tmpfilePath == "{$filePath}_{$chunk}.parttmp") {
                continue;
            }
            // Remove temp file if it is older than the max age and is not the current file
            if (preg_match('/\.(part|parttmp)$/', $file) && (filemtime($tmpfilePath) < time() - $maxFileAge)) {
                unlink($tmpfilePath);
            }
        }
        closedir($dir);
    }
    // Open temp file
    if (!$out = fopen("{$filePath}_{$chunk}.parttmp", "wb")) {
        die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream222."}, "id" : "id"}');
    }
    if (!empty($_FILES)) {
        if ($_FILES["file"]["error"] || !is_uploaded_file($_FILES["file"]["tmp_name"])) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 103, "message": "Failed to move uploaded file333."}, "id" : "id"}');
        }
        // Read binary input stream and append it to temp file
        if (!$in = fopen($_FILES["file"]["tmp_name"], "rb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream444."}, "id" : "id"}');
        }
    } else {
        if (!$in = fopen("php://input", "rb")) {
            die('{"jsonrpc" : "2.0", "error" : {"code": 101, "message": "Failed to open input stream555."}, "id" : "id"}');
        }
    }
    while ($buff = fread($in, 4096)) {
        fwrite($out, $buff);
    }
    fclose($out);
    fclose($in);
    rename("{$filePath}_{$chunk}.parttmp", "{$filePath}_{$chunk}.part");
    $index = 0;
    $done = true;
    for( $index = 0; $index < $chunks; $index++ ) {
        if ( !file_exists("{$filePath}_{$index}.part") ) {
            $done = false;
            break;
        }
    }
    if ($done)
    {
        $pathInfo = pathinfo($fileName);
        $hashStr = substr(md5($pathInfo['basename']),8,16);
        $hashName = time() . $hashStr . '.' .$pathInfo['extension'];

        $uploadPath = $uploadDir . DIRECTORY_SEPARATOR .$hashName;

        if (!$out = fopen($uploadPath, "wb"))
        {
            die('{"jsonrpc" : "2.0", "error" : {"code": 102, "message": "Failed to open output stream666."}, "id" : "id"}');
        }

        //flock($hander,LOCK_EX)文件锁
        if ( flock($out, LOCK_EX) ) {
            for( $index = 0; $index < $chunks; $index++ ) {
                if (!$in = fopen("{$filePath}_{$index}.part", "rb")) {
                    break;
                }
                while ($buff = fread($in, 4096)) {
                    fwrite($out, $buff);
                }
                fclose($in);
                unlink("{$filePath}_{$index}.part");
            }
            flock($out, LOCK_UN);
        }
        fclose($out);
        $response = [
            'success'=>true,
            'oldName'=>$oldName,
            'filePath'=>$uploadPath,
            //                'fileSize'=>$data['size'],
            'fileSuffixes'=>$pathInfo['extension'],          //文件后缀名
            //                'file_id'=>$data['id'],
        ];
        return json($response);
    }
    // Return Success JSON-RPC response
    die('{"jsonrpc" : "2.0", "result" : null, "id" : "id"}');
}

/**
 * @Notes:返回文件访问域名地址
 * @User: chenping
 * @email: 375129701@qq.com
 */
function _get_file_domain()
{
    $storage = get_option('storage');
    if (empty($storage['type'])||$storage['type'] == 'Local') {
        return cmf_get_domain()."/upload";
    }
    if ($storage['type'] != 'Local') {
        $storage = \app\common\lib\Storage::instance();
        return $storage->getDomain();
    }

}

/**
 * 加密密码
 * @param $string
 * @return bool|string
 */
function Passwordmd5($string)
{
    $data = md5($string) . "199801052818";
    $hash = password_hash($data, PASSWORD_DEFAULT);
    return $hash;
}

/**
 * 解析密码验证
 * @param $password
 * @return bool
 */
function PasswordVerify($password, $hash)
{
    $data = md5($password) . "199801052818";
    if (password_verify($data, $hash)) {
        return true;
    } else {
        return false;
    }
}

/**
 * @Notes:检查用系统是否开启注册验证
 * @User: chenping
 * @email: 375129701@qq.com
 * @return mixed
 */
function is_open_register()
{
    $config = get_option('system_setting');
    return $config['open_registration'];
}


/**
 * @Notes:产品订单号
 * @User: chenping
 * @email: 375129701@qq.com
 */
function product_number()
{
    return date('Ymd') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}

/**
 * @Notes:导入模板
 * @User: chenping
 * @email: 375129701@qq.com
 * @param $filePath
 * @param int $offset
 * @return array
 */
function exportTemplate($filePath,$offset=0)
{
    header("content-type:text/html;charset=utf-8");

    $reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');
    //载入excel文件
    $excel = $reader->load($filePath, $encode = 'utf-8');
    //读取第一张表
    $sheet = $excel->getSheet(0);
    //获取总行数
    $row_num = $sheet->getHighestRow();
    //获取总列数
    $col_num = $sheet->getHighestColumn();
    //数组形式获取表格数据
    $import_data = [];
    //excel 数组化
    $excelArr = $sheet->toArray();

    //头部数据
    $keys = array_filter(array_values($excelArr[1]));

    foreach ($excelArr as $k=>$v)
    {
        if($offset==$k||$k>$offset)
        {
            foreach ($keys  as $key=>$valu1e)
            {
                $import_data[$k][$keys[$key]] = $v[$key] ;
            }
        }
    }
    return $import_data;
}